#region File Header
//
// MatFileWriter.cs - Writes a Matlab v4 file
//
// Copyright (C) Javier Valcarce. BSD License
#endregion

#region Using Statements
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.IO;
#endregion

namespace Dsp
{

    /// <summary>
    /// Writes Matlab V4 files
    /// </summary>
    public class MatFileWriter 
    {
        class Header
        {
            public enum MatrixType 
            { 
                Double,
                Complex
            }

            public MatrixType Type;
            public int        Cols;
            public int        Rows;
            public string     Name;
            
 
            ASCIIEncoding     enc = new ASCIIEncoding();
            byte[]            cstr;
            int               mopt;
            int               imag;
            const byte        zero = 0x00;

            public void WriteOn(BinaryWriter bwr)
            {
                mopt = (BitConverter.IsLittleEndian) ? 0000 : 1000;
                imag = (Type == MatrixType.Complex ) ? 1    :    0;
                //
                cstr = enc.GetBytes(Name);
                //
                bwr.Write(mopt);
                bwr.Write(Rows);
                bwr.Write(Cols);
                bwr.Write(imag);
                bwr.Write(cstr.Length + 1);
                // name c style
                bwr.Write(cstr);
                bwr.Write(zero);
            }

        }

        FileStream    str;
        BinaryWriter  bwr;
        int           count;
        Header        h = new Header();

        #region Constructors
        public MatFileWriter(string file)
        {
            this.str = new FileStream(file, FileMode.Create);
            this.bwr = new BinaryWriter(str);
            
            count = 0;
        }
        #endregion

        #region Public Methods

        //public void Write(MatrixD matrix)
        //{
        //    Write(matrix, "");
        //}

        //public void Write(MatrixD matrix, string name)
        //{
        //    h.Type = Header.MatrixType.Double;
        //    h.Name = name;
        //    h.Rows = matrix.Rows;
        //    h.Cols = matrix.Cols;

        //    h.WriteOn(bwr);

        //    // Wait matrix data, column-wise
        //    for (int j = 0; j < matrix.Cols; j++)
        //    {
        //        for (int i = 0; i < matrix.Rows; i++)
        //        {
        //            bwr.Write(matrix[i, j]);
        //        }
        //    }
        //}


        /// <summary>
        /// Writes a two-dimensional array of doubles
        /// </summary>
        /// <param name="m">Matrix</param>
        /// <param name="name">Matrix's name</param>
        public void Write(double[,] m, string name)
        {
            
            h.Type = Header.MatrixType.Double;
            h.Name = name;
            h.Rows = m.GetLength(0);
            h.Cols = m.GetLength(1);
            h.WriteOn(bwr);

            // Wait matrix data, column-wise
            for (int j = 0; j < m.GetLength(1); j++)
            {
                for (int i = 0; i < m.GetLength(0); i++)
                {
                    bwr.Write(m[i, j]);
                }
            }
        }

        /// <summary>
        /// Writes a one-dimensional array of doubles
        /// </summary>
        /// <param name="v">Vector. Stored as a column matrix</param>
        /// <param name="name">Vector's name</param>
        public void Write(double[] v, string name)
        {

            h.Type = Header.MatrixType.Double;
            h.Name = name;
            h.Rows = v.Length;
            h.Cols = 1;
            h.WriteOn(bwr);

            // Wait matrix data, column-wise
            for (int i = 0; i < v.Length; i++)
            {
                bwr.Write(v[i]);
            }
        }


        /// <summary>
        /// Closes the Matlab file
        /// </summary>
        public void Close()
        {
            bwr.Close();
        }


        #endregion

    }
}